package com.tinem.platform.service.security.observable;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.tinem.platform.client.message.PushClient;
import com.tinem.platform.module.pojo.co.RedisKeyEnum;
import com.tinem.platform.module.pojo.enums.message.PushChannel;
import com.tinem.platform.module.pojo.vo.error.UserException;
import com.tinem.platform.module.pojo.vo.message.PushReq;
import com.tinem.platform.module.starter.sdk.MessageCode;
import com.tinem.platform.module.starter.web.context.GatewayContext;
import com.tinem.platform.service.security.config.ClientConfiguration;
import com.tinem.platform.service.security.service.VerificationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.HashMap;

/**
 * @author fzh
 * @version v1
 * @program: platform
 * @className ImageApi
 * @description TODO
 * @site 
 * @company 
 * @create 2020-09-28 10:08
 */
@Service
@SuppressWarnings("unchecked")
public class SendListener implements ApplicationListener<GenerateObservable> {
    @Autowired
    PushClient pushClient;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Value("${verification.code.sms.effective-time}")
    Duration smsCodeEffectiveTime;


    @Value("${verification.code.email.effective-time}")
    Duration emailCodeEffectiveTime;

    @Resource
    VerificationService verificationService;

    @Resource
    ClientConfiguration clientConfiguration;

    @Override
    public void onApplicationEvent(GenerateObservable event) {
        if(!StrUtil.equalsAnyIgnoreCase(event.getChannel().toUpperCase(),
                PushChannel.EMAIL.name(),PushChannel.SMS.name(),PushChannel.EMAIL_WITH_IMG_CODE.name())){
            return;
        }

        // 发送邮件验证码时需要校验 email_with_img_code
        if(StrUtil.equalsAnyIgnoreCase(event.getChannel().toUpperCase(),
                PushChannel.EMAIL_WITH_IMG_CODE.name())){
            // 校验图片验证码
            if(!verificationService.verification(null,event.getSource().getImgCodeId(),event.getSource().getImgCode()).isSuccess()){
                throw new UserException(MessageCode.THE_GRAPHIC_VERIFICATION_CODE_IS_INCORRECT);
            }
        }

        // 邮箱发送频率拦截
        String client = GatewayContext.getClient();
        String to = event.getSource().getTo();
        ClientConfiguration.Config config = clientConfiguration.getConfig().get(client);
        if(config != null){
            Duration effectiveTime = config.getEffectiveTime();
            String key = RedisKeyEnum.security_verification_code.getKey(client, to);
            // 五分钟只能发送一次
            if (redisTemplate.hasKey(key)) {
                throw new UserException(MessageCode.VERIFICATION_CODE_VALID_FOR_FIVE_MINUTES,String.valueOf(effectiveTime.toMinutes()));
            } else {
                redisTemplate.opsForValue().set(key,to,effectiveTime);
            }
        }



        // 生成验证码
        event.setCode(RandomUtil.randomString(event.getSource().getCodeCount()));
        if(event.getChannel().equalsIgnoreCase(PushChannel.SMS.name())){
            event.setCodeEffectiveTime(smsCodeEffectiveTime);
        }else{
            event.setCodeEffectiveTime(emailCodeEffectiveTime);
        }
        
        PushReq pushReq = new PushReq();
        pushReq.setPushChannel(PushChannel.ALI_EMAIL);
        pushReq.setExtMailSubject("RingSmiley");
        pushReq.setFrom("service@ringsmiley.com");
        pushReq.setTo(to);
        pushReq.setExtMailOpenEventMonitor(1);
        pushReq.setExtMailClickLinkEventMonitor(1);
        pushReq.setBody(event.getSource().getBody());
        pushReq.setParams(new HashMap(){
            {
                put("code", event.getCode());
            }
        });
        pushClient.push(pushReq);
    }
}
